package com.voicecomm.recognition;

import com.baidu.aip.speech.AipSpeech;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 语音识别服务
 * 使用百度AI语音识别API进行实时语音识别
 * 
 * @author VoiceComm Team
 * @version 1.0.0
 */
public class VoiceRecognitionService {
    
    private static final Logger logger = LoggerFactory.getLogger(VoiceRecognitionService.class);
    
    // 百度AI配置
    private final String appId;
    private final String apiKey;
    private final String secretKey;
    
    private AipSpeech client;
    private final ObjectMapper objectMapper;
    private final ExecutorService executorService;
    
    // 识别参数配置
    private static final String FORMAT = "pcm";
    private static final int RATE = 16000;
    private static final int CHANNEL = 1;
    private static final String CUID = "A4-B1-C1-3F-8B-3F";
    private static final int DEV_PID = 1537; // 中文普通话
    
    /**
     * 构造函数
     * 
     * @param appId 百度AI应用ID
     * @param apiKey 百度AI API Key
     * @param secretKey 百度AI Secret Key
     */
    public VoiceRecognitionService(String appId, String apiKey, String secretKey) {
        this.appId = appId;
        this.apiKey = apiKey;
        this.secretKey = secretKey;
        this.objectMapper = new ObjectMapper();
        this.executorService = Executors.newFixedThreadPool(4);
        
        initializeClient();
    }
    
    /**
     * 初始化百度AI客户端
     */
    private void initializeClient() {
        try {
            client = new AipSpeech(appId, apiKey, secretKey);
            
            // 设置网络连接参数
            client.setConnectionTimeoutInMillis(2000);
            client.setSocketTimeoutInMillis(60000);
            
            logger.info("百度AI语音识别客户端初始化成功");
        } catch (Exception e) {
            logger.error("初始化百度AI客户端失败", e);
            throw new RuntimeException("语音识别服务初始化失败", e);
        }
    }
    
    /**
     * 异步识别语音
     * 
     * @param audioData 音频数据
     * @return 识别结果Future
     */
    public CompletableFuture<RecognitionResult> recognizeAsync(byte[] audioData) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return recognize(audioData);
            } catch (Exception e) {
                logger.error("语音识别失败", e);
                return new RecognitionResult(false, "", 0.0, e.getMessage());
            }
        }, executorService);
    }
    
    /**
     * 同步识别语音
     * 
     * @param audioData 音频数据
     * @return 识别结果
     */
    public RecognitionResult recognize(byte[] audioData) {
        if (audioData == null || audioData.length == 0) {
            return new RecognitionResult(false, "", 0.0, "音频数据为空");
        }
        
        try {
            // 设置识别参数
            HashMap<String, Object> options = new HashMap<>();
            options.put("dev_pid", DEV_PID);
            options.put("cuid", CUID);
            
            // 调用百度AI语音识别API
//            JSONObject result = client.asr(audioData, FORMAT, RATE, CHANNEL, options);
            JSONObject result = client.asr(audioData, FORMAT, RATE, options);
            
            // 解析识别结果
            return parseRecognitionResult(result);
            
        } catch (Exception e) {
            logger.error("语音识别API调用失败", e);
            return new RecognitionResult(false, "", 0.0, "API调用失败: " + e.getMessage());
        }
    }
    
    /**
     * 解析识别结果
     * 
     * @param jsonResult JSON格式的识别结果
     * @return 解析后的识别结果
     */
    private RecognitionResult parseRecognitionResult(JSONObject jsonResult) {
        try {
            String jsonString = jsonResult.toString();
            JsonNode rootNode = objectMapper.readTree(jsonString);
            
            int errNo = rootNode.get("err_no").asInt();
            String errMsg = rootNode.has("err_msg") ? rootNode.get("err_msg").asText() : "";
            
            if (errNo == 0) {
                // 识别成功
                JsonNode resultNode = rootNode.get("result");
                if (resultNode != null && resultNode.isArray() && resultNode.size() > 0) {
                    String text = resultNode.get(0).asText();
                    double confidence = calculateConfidence(rootNode);
                    
                    // logger.debug("语音识别成功: {}", text);
                    return new RecognitionResult(true, text, confidence, "");
                } else {
                    return new RecognitionResult(false, "", 0.0, "识别结果为空");
                }
            } else {
                // 识别失败
                logger.warn("语音识别失败: err_no={}, err_msg={}", errNo, errMsg);
                return new RecognitionResult(false, "", 0.0, "识别失败: " + errMsg);
            }
            
        } catch (Exception e) {
            logger.error("解析识别结果失败", e);
            return new RecognitionResult(false, "", 0.0, "结果解析失败: " + e.getMessage());
        }
    }
    
    /**
     * 计算识别置信度
     * 
     * @param rootNode JSON根节点
     * @return 置信度值
     */
    private double calculateConfidence(JsonNode rootNode) {
        try {
            // 百度AI返回的结果中可能包含置信度信息
            if (rootNode.has("confidence")) {
                return rootNode.get("confidence").asDouble();
            }
            
            // 如果没有明确的置信度，根据err_no计算一个估计值
            int errNo = rootNode.get("err_no").asInt();
            if (errNo == 0) {
                return 0.9; // 成功识别时给一个较高的置信度
            } else {
                return 0.0;
            }
        } catch (Exception e) {
            logger.warn("计算置信度失败", e);
            return 0.5; // 默认中等置信度
        }
    }
    
    /**
     * 批量识别语音数据
     * 
     * @param audioDataList 音频数据列表
     * @return 识别结果列表
     */
    public CompletableFuture<RecognitionResult[]> recognizeBatch(byte[][] audioDataList) {
        return CompletableFuture.supplyAsync(() -> {
            RecognitionResult[] results = new RecognitionResult[audioDataList.length];
            
            for (int i = 0; i < audioDataList.length; i++) {
                try {
                    results[i] = recognize(audioDataList[i]);
                } catch (Exception e) {
                    logger.error("批量识别第{}个音频失败", i, e);
                    results[i] = new RecognitionResult(false, "", 0.0, "识别异常: " + e.getMessage());
                }
            }
            
            return results;
        }, executorService);
    }
    
    /**
     * 释放资源
     */
    public void shutdown() {
        if (executorService != null && !executorService.isShutdown()) {
            executorService.shutdown();
            logger.info("语音识别服务已关闭");
        }
    }
    
    /**
     * 语音识别结果类
     */
    public static class RecognitionResult {
        private final boolean success;
        private final String text;
        private final double confidence;
        private final String errorMessage;
        private final long timestamp;
        
        public RecognitionResult(boolean success, String text, double confidence, String errorMessage) {
            this.success = success;
            this.text = text != null ? text : "";
            this.confidence = confidence;
            this.errorMessage = errorMessage != null ? errorMessage : "";
            this.timestamp = System.currentTimeMillis();
        }
        
        public boolean isSuccess() {
            return success;
        }
        
        public String getText() {
            return text;
        }
        
        public double getConfidence() {
            return confidence;
        }
        
        public String getErrorMessage() {
            return errorMessage;
        }
        
        public long getTimestamp() {
            return timestamp;
        }
        
        @Override
        public String toString() {
            return String.format("RecognitionResult{success=%s, text='%s', confidence=%.2f, error='%s'}", 
                               success, text, confidence, errorMessage);
        }
    }
}
